package com.haike.pushjobs.config;

import com.baomidou.dynamic.datasource.creator.DataSourceCreator;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import lombok.var;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.AbstractDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * 解决 数据源未添加就使用数据库 报错.
 */
@Configuration
@AutoConfigureBefore(DynamicDataSourceAutoConfiguration.class)
@EnableConfigurationProperties(DynamicDataSourceProperties.class)
public class CustomDataSourceAutoConfiguration {

    @Autowired
    private DynamicDataSourceProperties properties;

    @Bean
    public DataSourceCreator dataSourceCreator() {
        return new CustomDataSourceCreator();
    }

    class CustomDataSourceCreator extends DataSourceCreator {

        @Override
        public DataSource createDataSource(DataSourceProperty dataSourceProperty) {
            try {
                // 创建Hikari数据源
                com.zaxxer.hikari.HikariDataSource dataSource = new com.zaxxer.hikari.HikariDataSource();
                dataSource.setJdbcUrl(dataSourceProperty.getUrl());
                dataSource.setUsername(dataSourceProperty.getUsername());
                dataSource.setPassword(dataSourceProperty.getPassword());
                dataSource.setDriverClassName(dataSourceProperty.getDriverClassName());
                dataSource.setPoolName(dataSourceProperty.getPoolName());

                // 应用全局Hikari配置
                applyGlobalHikariConfig(dataSource);

                // 测试连接
//                try (Connection connection = dataSource.getConnection()) {
//                    if (!connection.isValid(3000)) {
//                        throw new SQLException("连接无效");
//                    }
//                }

                return dataSource;
            } catch (Exception e) {
                // 连接失败时记录日志并返回特殊数据源
                System.err.println("数据源 " + dataSourceProperty.getPoolName() + " 初始化失败: " + e.getMessage());
                return new FailedDataSource(dataSourceProperty.getPoolName(), e);
            }
        }

//        public boolean support(DataSourceProperty dataSourceProperty) {
//            // 仅支持HikariCP数据源，如需支持Druid等其他类型，需添加相应逻辑
//            return true;
//        }

        private void applyGlobalHikariConfig(com.zaxxer.hikari.HikariDataSource dataSource) {
            var hikari = properties.getHikari();
            if (hikari != null) {
                // 应用全局Hikari配置
                if (hikari.getMaxPoolSize() != null) {
                    dataSource.setMaximumPoolSize(hikari.getMaxPoolSize());
                }
                if (hikari.getMinIdle() != null) {
                    dataSource.setMinimumIdle(hikari.getMinIdle());
                }
                if (hikari.getConnectionTimeout() != null) {
                    dataSource.setConnectionTimeout(hikari.getConnectionTimeout());
                }
                // 可以添加更多配置项...
            }
        }
    }

    // 自定义失败数据源，用于标记不可用的数据源
    static class FailedDataSource extends AbstractDataSource {

        private final String name;
        private final Exception exception;

        public FailedDataSource(String name, Exception exception) {
            this.name = name;
            this.exception = exception;
        }

        @Override
        public Connection getConnection() throws SQLException {
            throw new SQLException("数据源 " + name + " 连接失败", exception);
        }

        @Override
        public Connection getConnection(String username, String password) throws SQLException {
            throw new SQLException("数据源 " + name + " 连接失败", exception);
        }

        @Override
        public <T> T unwrap(Class<T> iface) throws SQLException {
            throw new SQLException("数据源 " + name + " 连接失败", exception);
        }

        @Override
        public boolean isWrapperFor(Class<?> iface) throws SQLException {
            throw new SQLException("数据源 " + name + " 连接失败", exception);
        }
    }
}